package com.wjh.rules.core.engine;

import com.wjh.rules.common.EngineResponse;
import com.wjh.rules.common.ResponseMessage;
import com.wjh.rules.common.RuleEntity;
import com.wjh.rules.core.factory.RuleUnitFactory;
import com.wjh.rules.core.rule.RuleUnit;
import com.wjh.rules.interfaces.LessRuleEngine;
import org.apache.commons.lang.StringUtils;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * @ClassName AbstractJpooRulesEngine
 * @Description:
 * @Author wjh
 * @Date 2020年6月19日
 */
public abstract class AbstractLessRulesEngine implements LessRuleEngine {

    //引擎拥有一个规则池，并能进行规则的增删改查
    protected LinkedBlockingDeque<RuleUnit> ll = new LinkedBlockingDeque<RuleUnit>();

    private ScriptEngineManager manager = new ScriptEngineManager();

    private ScriptEngine engine = manager.getEngineByName("js");

    @Override
    public abstract EngineResponse fire(Map<String, Object> fact);

    @Override
    public abstract EngineResponse fireFail(Map<String, Object> fact);

    @Override
    public EngineResponse del(String ruleId) {
        if (StringUtils.isBlank(ruleId)) {
            return EngineResponse.fail_op("参数错误,ruleId:" + ruleId);
        }
        RuleUnit del = null;
        for (RuleUnit each : ll) {
            String id = each.getId();
            if (StringUtils.equals(id, ruleId)) {
                del = each;
                break;
            }
        }
        if (del == null) {
            return EngineResponse.fail_op("规则池里面要删除的规则:[" + ruleId + "]");
        }
        ll.remove(del);
        return EngineResponse.ok_op();
    }

    @Override
    public EngineResponse add(RuleEntity ruleEntity) {
        ResponseMessage<RuleUnit> rm = RuleUnitFactory.create(ruleEntity);
        if (rm.getCode() == ResponseMessage.FAIL) {
            return EngineResponse.fail_op(rm.getMsg());
        }
        RuleUnit ru = rm.getData();
        ru.setScriptEngine(engine);
        ll.add(ru);
        return EngineResponse.ok_op();
    }

    @Override
    public EngineResponse addAll(List<RuleEntity> ruleEntitys) {
        ruleEntitys.forEach(ruleEntity -> add(ruleEntity));
        return EngineResponse.ok_op();
    }

    @Override
    public EngineResponse get(String ruleId) {
        if (StringUtils.isBlank(ruleId)) {
            return EngineResponse.fail_op("参数错误,ruleId:" + ruleId);
        }
        RuleUnit rule = null;
        for (RuleUnit each : ll) {
            String id = each.getId();
            if (StringUtils.equals(id, ruleId)) {
                rule = each;
                break;
            }
        }
        if (rule == null) {
            return EngineResponse.fail_op("规则池里面不存在规则:[" + ruleId + "]");
        }
        List<RuleUnit> list = new ArrayList<RuleUnit>();
        list.add(rule);
        return EngineResponse.ok_query(list);
    }

    @Override
    public EngineResponse update(RuleEntity ruleEntity) {
        if (ruleEntity == null) {
            return EngineResponse.fail_op("参数错误,RuleEntity对象为null");
        }
        String ruleId = ruleEntity.getId();
        if (StringUtils.isBlank(ruleId)) {
            return EngineResponse.fail_op("参数错误,ruleId:" + ruleId);
        }
        this.del(ruleId);
        this.add(ruleEntity);
        return EngineResponse.ok_op();
    }

    @Override
    public EngineResponse getRulePool() {
        List<RuleUnit> list = new ArrayList<RuleUnit>();
        if (ll == null || ll.isEmpty()) {
            return EngineResponse.ok_query(list);
        }
        for (RuleUnit each : ll) {
            list.add(each);
        }
        return EngineResponse.ok_query(list);
    }

    protected EngineResponse assebleFireResult(Map<String, List<String>> result) {
        EngineResponse er = new EngineResponse();
        if (result == null || result.isEmpty()) {
            er.setMatchCode(EngineResponse.ENGINE_MATCH_RES_FAIL);
            return er;
        }
        er.setMatchCode(EngineResponse.ENGINE_MATCH_RES_SUCC);
        er.setFireResult(result);
        return er;
    }

    protected EngineResponse assebleFireResult(Map<String, List<String>> result, List<RuleUnit> ruleUnits) {
        EngineResponse er = new EngineResponse();
        if (result == null || result.isEmpty()) {
            er.setMatchCode(EngineResponse.ENGINE_MATCH_RES_FAIL);
            return er;
        }
        er.setMatchCode(EngineResponse.ENGINE_MATCH_RES_SUCC);
        er.setFireResult(result);
        er.setQueryResult(ruleUnits);
        return er;
    }

}
